/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.michalwski.mpplayer;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import javax.microedition.lcdui.*;
import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.PlayerListener;
import javax.microedition.midlet.MIDlet;
import org.netbeans.microedition.lcdui.SplashScreen;
import org.netbeans.microedition.lcdui.pda.FileBrowser;

/**
 * @author Michal Piotrowski
 */
public class MPPlayer extends MIDlet implements CommandListener, PlayerListener, ItemStateListener{

    private Command exitCommand;
    private Command selectFileCommand;
    private Command pausePlayCommand;
    private Command resumePlayCommand;
    private Command nextFileCommand;
    private Command prevFileCommand;
    private Command moveForwardCommand;
    private Command moveBackwardCommand;
    private Command openFileBrowserCommand;
    
    private SplashScreen splashScreen;
    private boolean midletPaused;
    private FileBrowser fileBrowser;
    
    private Form playerForm;
    private Player musicPlayer;
    private Timer controllerThread;
    private Gauge progress;
    
    private Vector files;
    private int currentSongPos = 0;
    
    
    public MPPlayer(){
        exitCommand = new Command("Exit", Command.EXIT, 0);
        selectFileCommand = FileBrowser.SELECT_FILE_COMMAND;
        
        pausePlayCommand = new Command("Pause", Command.CANCEL, 0);
        resumePlayCommand = new Command("Resume", Command.CANCEL, 0);
        
        openFileBrowserCommand = new Command("Files", Command.BACK, 0);
        nextFileCommand = new Command("Next", Command.ITEM, 0);
        prevFileCommand = new Command("Prev", Command.ITEM, 0);
        moveForwardCommand = new Command(">>", Command.ITEM, 0);
        moveBackwardCommand = new Command("<<", Command.ITEM, 0);
        
        
    } 
    
    public void startApp() {
        if (midletPaused) {
            resumeMIDlet ();
        } else {
            startMIDlet ();
        }
        midletPaused = false;
    }
    
    public void pauseApp() {
        midletPaused = true;
    }
    
    public void destroyApp(boolean unconditional) {
    
    }
    
    public void commandAction(Command c, Displayable d) {
        System.out.print("d: "+d.toString()+" c: "+c.toString()+"\n");
        if (c == exitCommand) {
            exitMIDlet();
        } else if (d == fileBrowser) {
            if (c == selectFileCommand) {
                try {
                    prepareFiles();
                    switchDisplayable(null, getPlayer(openFile(currentSongPos)));
                } catch (Exception e) {
                    switchDisplayable(getExceptionAlert(e), getFileBrowser());
                }
            } else if (c == FileBrowser.SELECT_COMMAND) {
                System.out.print("SELECT "+fileBrowser.getSelectedFileURL()+"\n");
            }
        } else if (d == playerForm){
            if (c == pausePlayCommand) {
                System.out.print("Pause play\n");
                pausePlayback();
            } else if (c == resumePlayCommand) {
                resumePlayback();  
            } else if (c == openFileBrowserCommand) {
                switchDisplayable(null, getFileBrowser());
            } else if (c == nextFileCommand) {
                playNextPrevFile(1);
            } else if (c == prevFileCommand) {
                playNextPrevFile(-1);
            } else if (c == moveForwardCommand) {
                movePlayback(2);
            } else if (c == moveBackwardCommand) {
                movePlayback(-2);
            } 
        } else if (d == splashScreen && c == SplashScreen.DISMISS_COMMAND){
            switchDisplayable(null, getFileBrowser());
        }
        
    }
    
    private void startMIDlet(){
        switchDisplayable(null, getSplashScreen());
//        switchDisplayable(null, getFileBrowser());
    }
    
    private void resumeMIDlet(){
        
    }
    
    private void switchDisplayable(Alert alert, Displayable nextDisplayable) {                                            
        Display display = getDisplay();                                               
        if (alert == null) {
            display.setCurrent(nextDisplayable);
        } else {
            display.setCurrent(alert, nextDisplayable);
        }                                             
        // write post-switch user code here
    }

    private Display getDisplay() {
        return Display.getDisplay(this);
    }

    private SplashScreen getSplashScreen() {
        if (splashScreen == null) {                                 
            // write pre-init user code here
            splashScreen = new SplashScreen(getDisplay());                                    
            splashScreen.setTitle("MPPlayer");
            splashScreen.setCommandListener(this);
            splashScreen.setText("MP3 and WAV player");                                  
            // write post-init user code here
        }                         
        return splashScreen;
    }
    
    public FileBrowser getFileBrowser() {
        if (fileBrowser == null) {          
            fileBrowser = new FileBrowser(getDisplay());                                    
            fileBrowser.setTitle("MPPlayer File Browser");
            fileBrowser.setCommandListener(this);
            fileBrowser.addCommand(selectFileCommand);
            fileBrowser.addCommand(exitCommand);
            fileBrowser.addCommand(FileBrowser.SELECT_COMMAND);
//            fileBrowser.setFilter("mp3 wav");
        }                         
        return fileBrowser;
    }
    
    private void prepareFiles() throws IOException, MediaException{
        String selectedFileURL = fileBrowser.getSelectedFileURL();
        System.out.print(selectedFileURL+"\n");
        
        resetMusicPlayer();
        
        String selectedFileName = fileBrowser.getSelectedFile().getName();
        String parentDirURL = "file://"+fileBrowser.getSelectedFile().getPath();
        FileConnection parentDir = (FileConnection) Connector.open(parentDirURL);
        files = new Vector();
        Enumeration filesEnum = parentDir.list();
        int songPos = 0;
        while(filesEnum.hasMoreElements()) {
            String fileName = (String) filesEnum.nextElement();
            int dotPos = fileName.lastIndexOf('.')+1;
            if ( dotPos > 0) {
                String ext = fileName.substring(dotPos);
                if (ext.equalsIgnoreCase("mp3") || ext.equalsIgnoreCase("wav")) {
                    files.addElement(parentDirURL+"/"+fileName);
                    if (fileName.equalsIgnoreCase(selectedFileName)) {
                        currentSongPos = songPos;
                    }
                    songPos++;
                }
            }
        }
    }
    
    private String openFile(int pos) throws IOException, MediaException{
        String selectedFileURL = (String) files.elementAt(currentSongPos);
        musicPlayer = Manager.createPlayer(selectedFileURL);
        musicPlayer.addPlayerListener(this);
        return selectedFileURL;
    }
    
    private void resetMusicPlayer(){
        if (musicPlayer != null){
            try {
                musicPlayer.stop();
                musicPlayer.close();
                musicPlayer = null;
            } catch (MediaException ex) {
                System.out.print("Problems with music reset: "+ex.getMessage()+"\n");
            }
        }
        if (controllerThread != null) {
//            controllerThread.interrupt();
            controllerThread.cancel();
            controllerThread = null;
        }
        
        controllerThread = new Timer();
        
//        controllerThread = new Thread() {
//            public void run(){
//                try {
//                    while(true) {
//                        synchronized (progress){
//                            int value = (int) Math.floor((double)musicPlayer.getMediaTime() / (double)musicPlayer.getDuration() * 100.0);
//                            progress.setValue(value);
//                        }
//                        Thread.sleep(1000);
//                    }
//                } catch (InterruptedException ex) {
//                    System.out.print("I'am interupted: "+ex.getMessage()+"\n");
//                    
//                }
//            }
//        };
    }
    
    private Form getPlayer(String fileName) throws MediaException{
        if (playerForm == null) {
            playerForm = new Form("MP audio player");
            playerForm.addCommand(exitCommand);
            playerForm.addCommand(openFileBrowserCommand);
            playerForm.addCommand(pausePlayCommand);
            playerForm.addCommand(nextFileCommand);
            playerForm.addCommand(prevFileCommand);
            playerForm.addCommand(moveBackwardCommand);
            playerForm.addCommand(moveForwardCommand);
            playerForm.setCommandListener(this);
            progress = new Gauge("File name", true, 100, 0);
            playerForm.setItemStateListener(this);
        }
        progress.setLabel(fileName);
        playerForm.deleteAll();
        playerForm.append("Currently plaing:\n");
        playerForm.append(progress);
        play();
        return playerForm;
    }
    
    private void play() throws MediaException{
        progress.setValue(0);
        musicPlayer.start();
        
        TimerTask task  = new TimerTask() {
            public void run(){
                synchronized (progress){
                    int value = (int) Math.floor((double)musicPlayer.getMediaTime() / (double)musicPlayer.getDuration() * 100.0);
                    progress.setValue(value);
                }
            }
        };
        
        controllerThread.schedule(task, 1000, 1000);
//        controllerThread.start();
    }
    
    private void play(int value) {
       synchronized(progress){
            long now = (long) (0.01 * musicPlayer.getDuration() * value);
            try {
                musicPlayer.setMediaTime(now);
            } catch (MediaException ex) {
                System.out.print("Problems with moving playing: "+ex.getMessage()+"\n");
            }
       }
    }
    
    private void playNextPrevFile(int i) {
        try{
            setCurrentFile(i);
            resetMusicPlayer();
            switchDisplayable(null, getPlayer(openFile(currentSongPos)));
        } catch (Exception e) {
            switchDisplayable(getExceptionAlert(e), getFileBrowser());
        }
    }

    private void movePlayback(int i) {
        try {
            long diff = (long) (0.01 * musicPlayer.getDuration());
            musicPlayer.setMediaTime(musicPlayer.getMediaTime()+diff*i);
        } catch (MediaException ex) {
            switchDisplayable(getExceptionAlert(ex), getFileBrowser());
        }
        
    }
    
    private void exitMIDlet() {
        switchDisplayable (null, null);
        destroyApp(true);
        notifyDestroyed();
    }

    private Alert getExceptionAlert(Exception e) {
        Alert alert = new Alert("Exception", e.getMessage(), null, AlertType.ERROR);
        return alert;
    }

    private void pausePlayback() {
        try {
            musicPlayer.stop();
            playerForm.removeCommand(pausePlayCommand);
            playerForm.addCommand(resumePlayCommand);
        } catch (MediaException ex) {
            switchDisplayable(getExceptionAlert(ex), playerForm);
        }
    }
    
    private void resumePlayback() {
        try {
            musicPlayer.start();
            playerForm.removeCommand(resumePlayCommand);
            playerForm.addCommand(pausePlayCommand);
            
        } catch (MediaException ex) {
             switchDisplayable(getExceptionAlert(ex), playerForm);
        }
    }

    private void setCurrentFile(int diff) {
        try {
            files.elementAt(currentSongPos+diff);
            currentSongPos+=diff;
        } catch (ArrayIndexOutOfBoundsException e) {
            if (diff > 0) {
                currentSongPos=0;
            } else {
                currentSongPos = files.size()-1;
            }
        }
    }

    public void playerUpdate(Player player, String event, Object eventData) {
        if (event.equalsIgnoreCase(PlayerListener.END_OF_MEDIA)) {
            playNextPrevFile(1);
            
        }
    }

    public void itemStateChanged(Item item) {
        if (item == progress){
            play(progress.getValue());
        }
    }
}
